﻿using ExamRoomAllocationManagement.Dao;
using System.Data;
using System.Text.Json;
using Xmu.Stores.Models;

namespace Xmu.ExamRoomAllocationManagement.Services
{
    public class AutoAllocationService : ISingletonDependency
    {
        private IServiceProvider serviceProvider;
        private Repositories repo;
        public AutoAllocationService(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
            repo = serviceProvider.CreateScope().ServiceProvider.GetRequiredService<Repositories>();
        }
        public (bool success,object msg) CalcStatus(ExamRoomAllocation allocation)
        {
            if (allocation == null)
            {
                Console.WriteLine("CalcStatus:allocation is null");
            }
            if (!CheckDepartmentDiff(allocation))
            {
                allocation.AllocationStatus = AllocationStatus.UnableToAllocate;
                repo.DbContex.SaveChanges();
                return (false,"部门相同");
            }
            if(!CheckNotBothNew(allocation))
            {
                allocation.AllocationStatus = AllocationStatus.UnableToAllocate;
                repo.DbContex.SaveChanges();
                return (false,"都是新老师");
            }
            if(!CheckGenderDiff(allocation))
            {
                allocation.AllocationStatus = AllocationStatus.AllocationWithIssues;
                repo.DbContex.SaveChanges();
                return (false,"性别相同");
            }
            if (!CheckParticipatedDiff(allocation))
            {
                allocation.AllocationStatus = AllocationStatus.AllocationWithIssues;
                repo.DbContex.SaveChanges();
                return (false,"不满足老带新");
            }
            return (true,"ok");
        }

        public bool CheckGenderDiff(ExamRoomAllocation allocation)
        {
            return allocation.Registration1.Gender != allocation.Registration2.Gender;
        }

        public bool CheckDepartmentDiff(ExamRoomAllocation allocation)
        {
            return allocation.Registration1.Workplace != allocation.Registration2.Workplace;
        }

        public bool CheckParticipatedDiff(ExamRoomAllocation allocation)
        {
            return allocation.Registration1.ParticipatedLastYear != allocation.Registration2.ParticipatedLastYear;
        }
        public bool CheckNotBothNew(ExamRoomAllocation allocation)
        {
            return allocation.Registration1.ParticipatedLastYear || allocation.Registration2.ParticipatedLastYear;
        }

        public void setStatus()
        {
            foreach(var item in repo.ExamRoomAllocations)
            {
                if (item.Registration1.Workplace == item.Registration2.Workplace || (!item.Registration1.ParticipatedLastYear && !item.Registration1.ParticipatedLastYear))
                    item.AllocationStatus = AllocationStatus.AllocationWithIssues;
                else
                    item.AllocationStatus = AllocationStatus.CorrectAllocation;
                repo.DbContex.SaveChanges();
            }
        }

        public bool coreItems(List<Registration> teachers)
        {
            return false;
        }

        public bool trap1(Registration t, List<Registration> registrations, int newCount)
        {
            //如果对于一个新老师来说，所有的老老师都和他部门相同，则无法分配
            if (!t.ParticipatedLastYear || newCount == 0)
                for (int i = 0; i < registrations.Count; i++) { if (registrations[i].Workplace != t.Workplace && registrations[i].ParticipatedLastYear) { return false; } }
            return true;
        }

        public int? trap2(Registration t, List<Registration> registrations)
        {
            //如果所有的异性和他部门相同，就挑同性的
            for (int i = 0; i < registrations.Count; i++) { if (t.ID != registrations[i].ID && t.Gender != registrations[i].Gender && t.Workplace != registrations[i].Workplace && registrations[i].ParticipatedLastYear) { return i; } }
            return null;
        }

        public void BuildAllocation(ExamRoomAllocation allocation)
        {             
            allocation.Exam = repo.Exams.FirstOrDefault(exam => exam.ExamId == allocation.ExamId);
            allocation.ExamRoom = repo.ExamRooms.FirstOrDefault(room => room.ExamRoomId == allocation.ExamRoomId);
            allocation.Registration1 = repo.Registrations.FirstOrDefault(reg => reg.ID == allocation.Registration1ID);
            allocation.Registration2 = repo.Registrations.FirstOrDefault(reg => reg.ID == allocation.Registration2ID);
        }

        public void indata(List<ExamRoomAllocation> examRoomAllocations)
        {
            //把分配结果装入repo中
            foreach (var item in examRoomAllocations)
            {
                item.Exam = repo.Exams.First();//随便设一个值，防止为空
                item.ExamId = item.Exam.ExamId;
                BuildAllocation(item);

                string json = JsonSerializer.Serialize(item, new JsonSerializerOptions
                {
                    WriteIndented = true // 如果希望输出格式化的 JSON，可以设置 WriteIndented 为 true
                });
                Console.WriteLine("item:" + json);
                repo.ExamRoomAllocations.Add(item);
                repo.DbContex.SaveChanges();
            }
            setStatus();
        }


        //自动排考算法
        public (bool success, string msg) AutoAllocate()
        {
            //获得待排教师集合
            List<Registration> teachers = repo.Registrations.ToList();
            //存储排考结果
            List<ExamRoomAllocation> examRoomAllocations = new List<ExamRoomAllocation>();
            int elderCount = 0;
            int newCount = 0;
            foreach (var teacher in teachers)
            {
                //计算新老的数量
                if (teacher.ParticipatedLastYear) elderCount++;
                else newCount++;
            }
            List<ExamRoom> examRooms = repo.ExamRooms.ToList();
            //设置状态
            foreach(var item in examRoomAllocations)
                item.AllocationStatus = AllocationStatus.UnableToAllocate;
            //遍历教师集合，挑取一位新老师
            for (int i = 0; i < teachers.Count; i++)
            {
                //新老师挑完了就挑老老师
                if ((newCount > 0 && !teachers[i].ParticipatedLastYear) || newCount == 0)
                {
                    int? intrap2 = trap2(teachers[i], teachers);
                    if (intrap2 == null)
                    {
                        //挑同性的
                        for (int j = 0; j < teachers.Count; j++)
                        {
                            if (teachers[j].ParticipatedLastYear && teachers[j].Workplace != teachers[i].Workplace)
                            {
                                if (examRooms.Count == 0)
                                    break;
                                //选择一个考场，进行分配
                                ExamRoom aroom = examRooms.First<ExamRoom>();
                                ExamRoomAllocation entity = new ExamRoomAllocation();
                                entity.ExamRoom = aroom;
                                entity.ExamRoomId = aroom.ExamRoomId;
                                entity.Registration1 = teachers[i];
                                entity.Registration1ID = teachers[i].ID;
                                entity.Registration2 = teachers[j];
                                entity.Registration2ID = teachers[j].ID;
                                examRoomAllocations.Add(entity);

                                //去掉这个考场，表示分配好了，然后也摘除已分配的老师
                                examRooms.Remove(aroom);
                                teachers.Remove(teachers[i]);
                                if (i < j) j--;
                                teachers.Remove(teachers[j]);
                                //外层重新循环，因为队列里面的元素个数改变了
                                i = -1;
                                if (newCount > 0) newCount--;
                                break;
                            }

                        }

                    }
                    else
                    {
                        //挑出两位老师
                        if (examRooms.Count == 0)
                            break;
                        ExamRoom aroom = examRooms.First<ExamRoom>();
                        ExamRoomAllocation entity = new ExamRoomAllocation();
                        entity.ExamRoom = aroom;
                        entity.ExamRoomId = aroom.ExamRoomId;
                        entity.Registration1 = teachers[i];
                        entity.Registration1ID = teachers[i].ID;
                        entity.Registration2 = teachers[(int)intrap2];
                        entity.Registration2ID = teachers[(int)intrap2].ID;
                        examRoomAllocations.Add(entity);

                        //删除这些元素
                        examRooms.Remove(aroom);
                        teachers.Remove(teachers[i]);
                        int two = i < (int)intrap2 ? (int)intrap2 - 1 : (int)intrap2;
                        teachers.Remove(teachers[two]);
                        i = -1;
                        if (newCount > 0) newCount--;
                    }
                }
            }
            //直到集合为空，若不为空直接二次分配
            if (examRooms.Count<ExamRoom>() != 0)
            {
                for (int y = 0; y < 10; y++)
                {
                    if (examRooms.Count == 0)
                        break;
                    //挑出一位老师
                    Registration teacher1 = teachers.First<Registration>();
                    for (int i = 0; i < examRoomAllocations.Count; i++)
                    {
                        //如果一个考场的两个老师所属部门与这位老师都不相同，可交换
                        if (teacher1.Workplace != examRoomAllocations[i].Registration1.Workplace && teacher1.Workplace != examRoomAllocations[i].Registration2.Workplace)
                        {
                            //把考场中的其中一位老老师和未分配的老师进行交换
                            if (examRoomAllocations[i].Registration1.ParticipatedLastYear)
                            {
                                examRoomAllocations[i].Registration1ID = teacher1.ID;
                                Registration temp = new Registration();
                                temp = examRoomAllocations[i].Registration1;
                                examRoomAllocations[i].Registration1 = teacher1;
                                teachers.Remove(teacher1);
                                teachers.Add(temp);
                                break;
                            }
                            else if (examRoomAllocations[i].Registration2.ParticipatedLastYear)
                            {
                                examRoomAllocations[i].Registration2ID = teacher1.ID;
                                Registration temp = new Registration();
                                temp = examRoomAllocations[i].Registration2;
                                examRoomAllocations[i].Registration2 = teacher1;
                                teachers.Remove(teacher1);
                                teachers.Add(temp);
                                break;
                            }

                        }
                    }
                    //重新分配未分配的老师群（按最低要求）
                    for (int i = 0; i < teachers.Count; i++)
                    {
                        for (int j = 0; j < teachers.Count; j++)
                        {
                            if (examRooms.Count == 0)
                                break;
                            if (teachers[i].ID != teachers[j].ID && teachers[i].Workplace != teachers[j].Workplace)
                            {
                                ExamRoom aroom = examRooms.First<ExamRoom>();
                                ExamRoomAllocation entity = new ExamRoomAllocation();
                                entity.ExamRoom = aroom;
                                entity.ExamRoomId = aroom.ExamRoomId;
                                entity.Registration1 = teachers[i];
                                entity.Registration1ID = teachers[i].ID;
                                entity.Registration2 = teachers[j];
                                entity.Registration2ID = teachers[j].ID;
                                examRoomAllocations.Add(entity);
                                examRooms.Remove(aroom);
                                teachers.Remove(teachers[i]);
                                if (i < j) j--;
                                teachers.Remove(teachers[j]);
                                i = -1;
                                break;

                            }
                        }
                    }
                    //重复上述过程，直到examRooms为空（或者重复10次结束，返回无法分配）。
                }

            }
            //最后把不能分配的老师强制分配
            if (examRooms.Count != 0)
            {
                for(int i = 0;i < examRooms.Count;i++)
                {
                    ExamRoomAllocation entity = new ExamRoomAllocation();
                    entity.ExamRoom = examRooms[i];
                    entity.Registration1 = teachers.First<Registration>();
                    entity.Registration1ID = entity.Registration1.ID;
                    teachers.Remove(entity.Registration1);
                    entity.Registration2 = teachers.First<Registration>();
                    entity.Registration2ID = entity.Registration2.ID;
                    teachers.Remove(entity.Registration2);
                    examRoomAllocations.Add(entity);
                }
            }

            //再调整分配，使少数性别尽量分散
            int maleAllocatedCount = 0;
            int femaleAllocatedCount = 0;
            foreach (var examAllocation in examRoomAllocations)
            {
                maleAllocatedCount = examAllocation.Registration1.Gender == Gender.Male ? maleAllocatedCount + 1 : maleAllocatedCount;
                femaleAllocatedCount = examAllocation.Registration1.Gender == Gender.Female ? femaleAllocatedCount + 1 : femaleAllocatedCount;
                maleAllocatedCount = examAllocation.Registration2.Gender == Gender.Male ? maleAllocatedCount + 1 : maleAllocatedCount;
                femaleAllocatedCount = examAllocation.Registration2.Gender == Gender.Female ? femaleAllocatedCount + 1 : femaleAllocatedCount;
            }
            if (maleAllocatedCount < femaleAllocatedCount)
            {
                int[] indexList = new int[maleAllocatedCount];
                int tapeLength = 0;
                if (maleAllocatedCount > 1) { tapeLength = (examRoomAllocations.Count - 1) / (maleAllocatedCount - 1); }
                for (int i = 0; i < maleAllocatedCount; i++)
                {
                    if (i == 0)
                        indexList[i] = 0;
                    else if (i == 1)
                        indexList[i] = examRoomAllocations.Count - 1;
                    else
                        indexList[i] = indexList[i - 2] + (int)Math.Pow(-1, i - 2) * tapeLength;
                }
                for (int i = 0; i < maleAllocatedCount; i++) { Console.WriteLine(indexList[i]); }
                int it = 0;
                for (int i = 0; i < examRoomAllocations.Count; i++)
                {
                    if (it >= maleAllocatedCount) break;
                    if (examRoomAllocations[i].Registration1.Gender == Gender.Male || examRoomAllocations[i].Registration2.Gender == Gender.Male)
                    {
                        if (indexList[it] != i)
                        {
                            //交换两个考场的分配
                            Registration temp = new Registration();
                            temp = examRoomAllocations[i].Registration1;
                            examRoomAllocations[i].Registration1 = examRoomAllocations[indexList[it]].Registration1;
                            examRoomAllocations[indexList[it]].Registration1 = temp;

                            temp = examRoomAllocations[i].Registration2;
                            examRoomAllocations[i].Registration2 = examRoomAllocations[indexList[it]].Registration2;
                            examRoomAllocations[indexList[it]].Registration2 = temp;

                            Guid temp2;
                            temp2 = examRoomAllocations[i].Registration1ID;
                            examRoomAllocations[i].Registration1ID = examRoomAllocations[indexList[it]].Registration1ID;
                            examRoomAllocations[indexList[it]].Registration1ID = temp2;

                            temp2 = examRoomAllocations[i].Registration2ID;
                            examRoomAllocations[i].Registration2ID = examRoomAllocations[indexList[it]].Registration2ID;
                            examRoomAllocations[indexList[it]].Registration2ID = temp2;

                            it++;
                        }
                        else
                            it++;
                    }
                }

            }
            else if (maleAllocatedCount > femaleAllocatedCount)
            {
                int[] indexList = new int[femaleAllocatedCount];
                int tapeLength = 0;
                if (femaleAllocatedCount > 1) { tapeLength = (examRoomAllocations.Count - 1) / (femaleAllocatedCount - 1); }
                for (int i = 0; i < femaleAllocatedCount; i++)
                {
                    if (i == 0)
                        indexList[i] = 0;
                    else if (i == 1)
                        indexList[i] = examRoomAllocations.Count - 1;
                    else
                        indexList[i] = indexList[i - 2] + (int)Math.Pow(-1, i - 2) * tapeLength;
                }
                for (int i = 0; i < femaleAllocatedCount; i++) { Console.WriteLine(indexList[i]); }
                int it = 0;
                for (int i = 0; i < examRoomAllocations.Count; i++)
                {
                    if (it >= femaleAllocatedCount) break;
                    if (examRoomAllocations[i].Registration1.Gender == Gender.Female || examRoomAllocations[i].Registration2.Gender == Gender.Female)
                    {
                        if (indexList[it] != i)
                        {
                            Registration temp = new Registration();
                            temp = examRoomAllocations[i].Registration1;
                            examRoomAllocations[i].Registration1 = examRoomAllocations[indexList[it]].Registration1;
                            examRoomAllocations[indexList[it]].Registration1 = temp;

                            temp = examRoomAllocations[i].Registration2;
                            examRoomAllocations[i].Registration2 = examRoomAllocations[indexList[it]].Registration2;
                            examRoomAllocations[indexList[it]].Registration2 = temp;

                            Guid temp2;
                            temp2 = examRoomAllocations[i].Registration1ID;
                            examRoomAllocations[i].Registration1ID = examRoomAllocations[indexList[it]].Registration1ID;
                            examRoomAllocations[indexList[it]].Registration1ID = temp2;

                            temp2 = examRoomAllocations[i].Registration2ID;
                            examRoomAllocations[i].Registration2ID = examRoomAllocations[indexList[it]].Registration2ID;
                            examRoomAllocations[indexList[it]].Registration2ID = temp2;

                            it++;
                        }
                        else
                            it++;
                    }
                }

            }
            indata(examRoomAllocations);
            return (true, "success");

        }

    }
}
